package com.example.myapplication.JavaParser

import com.google.common.base.CaseFormat
import java.io.File
import java.io.FileWriter

/**
 * @description:
 *
 * @author: wangrongfeng
 *
 * @create: 2023-07-11 17:44
 **/


fun main(args: Array<String>) {
//    val appKotlin =
//        "C:\\Users\\Rong\\AndroidStudioProjects\\dfdj-android2\\dfdj-android\\app\\src\\main\\java\\com\\daofeng\\peiwan"
//    val appKotlin = "C:\\Users\\Rong\\AndroidStudioProjects\\dfdj-android2\\dfdj-android\\live\\src\\main\\java\\com\\daofeng\\live"
    //val appKotlin = "C:\\Users\\Rong\\AndroidStudioProjects\\dfdj-android2\\dfdj-android\\order\\src\\main\\java\\com\\daofeng\\order"
//    val appKotlin = "C:\\Users\\Rong\\AndroidStudioProjects\\dfdj-android2\\dfdj-android\\baselibrary\\src\\main\\java\\com\\daofeng"
    //val appKotlin = "C:\\Users\\Rong\\AndroidStudioProjects\\dfdj-android2\\dfdj-android\\im\\src\\main\\java\\com\\daofeng\\im"
//    val appKotlin =   "C:\\Users\\Rong\\AndroidStudioProjects\\dfdj-android2\\dfdj-android\\chatroom\\src\\main\\java\\com\\daofeng\\chatroom"
    //val appKotlin = "C:\\Users\\Rong\\AndroidStudioProjects\\dfdj-android2\\dfdj-android\\app\\src\\main\\java\\com\\daofeng\\peiwan"


//
//    val appKotlin = "C:\\Users\\Rong\\AndroidStudioProjects\\dfdj-android2\\dfdj-android\\pageCommon\\src\\main\\java\\com\\daofeng\\common\\game\\treasurebox"
//    printDirByRecursive(File(appKotlin), 0)


    KtParser().init(File("C:\\Users\\Rong\\AndroidStudioProjects\\dfdj-android2\\dfdj-android\\app\\src\\xxyy\\java\\com\\daofeng\\peiwan\\mvvm\\mine\\MineXxFragment.kt"))
}

fun printDirByRecursive(dir: File, level: Int) {
    //获取这个目录下所有的子文件和子目录的数组。
    val files = dir.listFiles()
    //遍历这个数组，取出每个File对象
    if (files != null) {
        for (f in files) {
            //判断这个File是否是一个文件，是：
            if (f.isFile) {
                if (f.getName().endsWith(".kt")) {
                    KtParser().init(f)
                }
            } else { //否则就是一个目录，继续递归
                //递归调用
                printDirByRecursive(f, level + 1)
            }
        }
    }
}

class Node {
    var viewName = ""
    var preNode: Node? = null
}


class KtParser {
    val bindFileApp =
        File("C:\\Users\\Rong\\AndroidStudioProjects\\dfdj-android2\\dfdj-android\\app\\build\\generated\\data_binding_base_class_source_out\\xxyyDebugAlpha\\out\\com\\daofeng\\peiwan\\databinding");
    val bindFileChatRoom =
        File("C:\\Users\\Rong\\AndroidStudioProjects\\dfdj-android2\\dfdj-android\\chatroom\\build\\generated\\data_binding_base_class_source_out\\xxyyDebugAlpha\\out\\com\\daofeng\\chatroom\\databinding");
    val bindFileBasel =
        File("C:\\Users\\Rong\\AndroidStudioProjects\\dfdj-android2\\dfdj-android\\baselibrary\\build\\generated\\data_binding_base_class_source_out\\xxyyDebugAlpha\\out\\com\\daofeng\\baselibrary\\databinding");
    val bindFileLive =
        File("C:\\Users\\Rong\\AndroidStudioProjects\\dfdj-android2\\dfdj-android\\live\\build\\generated\\data_binding_base_class_source_out\\xxyyDebugAlpha\\out\\com\\daofeng\\live\\databinding");

    val layoutApp =
        File("C:\\Users\\Rong\\AndroidStudioProjects\\dfdj-android2\\dfdj-android\\app\\src\\main\\res\\layout");
    val layoutChatRoom =
        File("C:\\Users\\Rong\\AndroidStudioProjects\\dfdj-android2\\dfdj-android\\chatroom\\src\\main\\res\\layout");
    val layoutBasel =
        File("C:\\Users\\Rong\\AndroidStudioProjects\\dfdj-android2\\dfdj-android\\live\\src\\main\\res\\layout");
    val layoutLive =
        File("C:\\Users\\Rong\\AndroidStudioProjects\\dfdj-android2\\dfdj-android\\baselibrary\\src\\main\\res\\layout");


    fun init(file: File) {
        parseKotlinFile(file)
    }

    val nodes = mutableListOf<Node>()
    val xmlNodes = mutableListOf<Node>()
    val bindingFiles = mutableListOf<String>()

    fun findBindingFile(bindingLayout: String): File? {
        val array = arrayOf(bindFileApp, bindFileBasel, bindFileLive, bindFileChatRoom)
        array.forEach {
            it.listFiles().forEach { file: File ->
                if (file.name.equals(bindingLayout)) {
                    return file
                }
            }
        }
        return null
    }

    fun findLayoutFile(bindingLayout: String): File? {
        val array = arrayOf(layoutApp, layoutLive, layoutBasel, layoutChatRoom)
        array.forEach {
            it.listFiles().forEach { file: File ->
                if (file.name.equals(bindingLayout)) {
                    return file
                }
            }
        }
        return null
    }

    fun fileNamePick(name: String, line: String, viewId: String): String {
        val name1 = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, name)
        val name2 = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, name)
        val array = arrayOf(name, name1, name2)
        val tags = arrayOf(".", " ", ")", "?", "!", ",")
        array.forEach {
            if (line.contains("mBinding") || line.contains("import") || line.contains("R.id.") ||
                line.contains("R.layout")
            ) {
                return ""
            }
            tags.forEach { tag ->
                if (line.contains("$it$tag")) {
                    return line.replace("$it$tag", "$viewId$tag")
                }
            }
        }
        return ""
    }


    fun findViews(bindingLayout: String, preNode: Node?) {
        val file = findBindingFile(bindingLayout)
        file?.let {
            val layoutCode = file.readLines()
            var tag2 = "R.layout."
            run loop@{
                layoutCode.forEach {
                    if (it.contains(tag2) && it.contains(",")) {
                        val layout = it.substring(it.indexOf(tag2) + tag2.length).let { it2 ->
                            it2.substring(0, it2.indexOf(","))
                        }
                        findLayout(layout + ".xml", null)
                        return@loop
                    }
                }
            }

            val tag1 = "  public final "
            layoutCode.filter { line -> line.startsWith(tag1) && line.endsWith(";") }
                .forEach { field ->
                    val str =
                        field.substring(field.indexOf(tag1) + tag1.length, field.length - 1)
                            .split(" ")
                    if (str[0].endsWith("Binding")) {
                        val node = Node().apply {
                            this.viewName = str[1]
                            this.preNode = preNode
                        }
                        nodes.add(node)
                        findViews(str[0] + ".java", node)
                        bindingFiles.add(str[1])
                    } else {
                        nodes.add(Node().apply {
                            this.viewName = str[1]
                            this.preNode = preNode
                        })
                    }
                }
        }
    }

    data class AddID(val line: Int, val id: String)

    fun findLayout(layout: String, preNode: Node?) {
        val file = findLayoutFile(layout)
        file?.let {
            val xmlCole = it.readLines().toMutableList()
            var isBinding = false
            var includeTag = false
            var isincludeId = false
            var tagLayout = "layout=\"@layout/"
            var layoutId = ""
            var includeIndex = 0
            var addIdList = mutableListOf<AddID>()
            xmlCole.forEachIndexed { index, line ->
                if (line.contains("<layout xmlns:")) {
                    isBinding = true
                }

                if (line.contains("<include")) {
                    includeTag = true
                    isincludeId = false
                    includeIndex = index
                }
                if (includeTag) {
                    if (line.contains(tagLayout)) {
                        layoutId =
                            line.substring(line.indexOf(tagLayout) + tagLayout.length).let { it2 ->
                                it2.substring(0, it2.indexOf("\""))
                            }
                    }
                    if (line.contains("android:id=")) {
                        isincludeId = true
                    }
                    if (line.contains("/>")) {
                        includeTag = false
                        if (!isincludeId) {
                            addIdList.add(
                                AddID(
                                    (includeIndex + 1 + addIdList.size),
                                    "            android:id=\"@+id/$layoutId\""
                                )
                            )
                        }
                    }
                }

//                val tag1 = "android:id=\"@+id/"
//                if (line.contains(tag1)) {
//                    val id = line.substring(line.indexOf(tag1) + tag1.length).let { it2 ->
//                        it2.substring(0, it2.indexOf("\""))
//                    }
//                    xmlNodes.add(Node().apply {
//                        this.viewName = id
//                        this.preNode = preNode
//                    })
//                }
            }

            if (addIdList.size > 0) {
                val stringBuilder = StringBuilder()
                addIdList.forEach {
                    xmlCole.add(it.line, it.id)
                }
                xmlCole.forEachIndexed { index, line ->
                    stringBuilder.appendLine(line)
                }
                val writer = FileWriter(file.absolutePath)
                writer.write(stringBuilder.toString())
                writer.close()
            }

            if (!isBinding) {
                val stringBuilder = StringBuilder()
                xmlCole.forEachIndexed { index, line ->
                    if (index == 1) {
                        stringBuilder.appendLine("<layout xmlns:app=\"http://schemas.android.com/apk/res-auto\">")
                    }
                    if (!line.contains("xmlns:app=\"http://schemas.android.com/apk/res-auto\"")) {
                        stringBuilder.appendLine(line)
                    }
                    if (index == xmlCole.lastIndex) {
                        stringBuilder.appendLine("</layout>")
                    }
                }
                val writer = FileWriter(file.absolutePath)
                writer.write(stringBuilder.toString())
                writer.close()
            }

        }
    }

    fun getViewPre(node: Node, link: String): String {
        if (node.preNode != null) {
            val name = filesFormat(node.preNode!!.viewName)
            return getViewPre(node.preNode!!, ("${name}.$link"))
        }
        if (bindingFiles.contains(link)) {
            return "mBinding.$link.root"
        }
        return "mBinding.$link"
    }

    fun filesFormat(str: String): String {
        if (str.contains("_")) {
            return CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, str)
        }
        return str;
    }

    fun printNode(node: Node, link: String) {
        if (node.preNode != null) {
            printNode(node.preNode!!, link)
        }
        println(node.viewName + "->" + link)
    }

    private fun parseKotlinFile(file: File) {
        var codeList = file.readLines().toMutableList()

        val bindings = mutableListOf<String>()
        val synthetic = "kotlinx.android.synthetic.main."
        codeList.filter { it.contains(synthetic) }.forEach {
            val layout = it.substring(it.indexOf(synthetic) + synthetic.length).let { it2 ->
                it2.substring(0, it2.indexOf("."))
            }
            bindings.add(layout)
        }

        if (bindings.size == 0) {
            return
        }

        val bindingLayout =
            CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, bindings[0]) + "Binding.java"
        findViews(bindingLayout, null)

//        bindings.forEach { layout ->
//            val bindingLayout =
//                CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, layout) + "Binding.java"
//            findViews(bindingLayout, null)
//        }

        val stringBuilder = StringBuilder()
        codeList.forEachIndexed { index, line ->
            nodes.forEach { n ->
                val name = filesFormat(n.viewName)
                val viewId = getViewPre(n, name)
                val replayId = fileNamePick(n.viewName, line, viewId)
                if (replayId != "") {
                    codeList[index] = replayId
                }
            }
        }
        codeList.removeIf { it.contains(synthetic) }
//        nodes.forEach { n ->
//            printNode(n,"")
//        }
        codeList.forEach {
            stringBuilder.appendLine(it)
        }
//
        val writer = FileWriter(file.absolutePath)
        writer.write(stringBuilder.toString())
        writer.close()


//        println(stringBuilder)

//        val views = mutableListOf<String>()
//        codeList.forEach {
//            if (it.contains("R.layout.")) {
//                val layout = it.substring(it.indexOf("R.layout.") + "R.layout.".length)
//                val bindingLayout =
//                    CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, layout) + "Binding.java"
//                bindFile.listFiles().forEach { file: File ->
//                    if (file.name.equals(bindingLayout)) {
//                        val layoutCode = file.readLines()
//                        layoutCode.forEach { line ->
//                            if (line.contains("id = R.id.")) {
//                                val id = line.substring(
//                                    line.indexOf("id = R.id.") + "id = R.id.".length,
//                                    line.length - 1
//                                )
//                                views.add(id)
//                            }
//                        }
//                        println(layoutCode)
//                    }
//                }
//            }
//        }

//        val stringBuilder = StringBuilder()
//        codeList.forEachIndexed { index, line ->
//            views.filter { id -> line.contains(id) }.let { list ->
//                list.forEach { item ->
//                    val view =
//                        "mBinding." + CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_HYPHEN, item)
//                    codeList[index] = line.replace(item, view)
//                }
//            }
//        }


//        println(codeList)
//        CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, "test_data")

    }


}


